#ifndef Safe_Queue
#define Safe_Queue

#include <queue>
#include <pthread.h>

using namespace std;

template<typename T>
class SafeQueue {

    typedef void (*ReleaseFunc)(T &);

    private:

    pthread_cond_t cond;
    pthread_mutex_t mtx;

    queue<T> queue;

    bool working;

    ReleaseFunc releaseFunc;

    public:

    SafeQueue(ReleaseFunc releaseFunc) : releaseFunc(releaseFunc) {
        pthread_mutex_init(&mtx, nullptr);
        pthread_cond_init(&cond, nullptr);
    }

    ~SafeQueue() {
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mtx);
    }

    //入列
    void enqueue(T item) {
        if (!item) return;
        pthread_mutex_lock(&mtx);
        if (working) {
            queue.push(item);
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mtx);
        } else {
            if (releaseFunc)
                releaseFunc(item);
        }
        pthread_mutex_unlock(&mtx);
    }

    //出列
    bool dequeue(T &item) {
        pthread_mutex_lock(&mtx);
        //queue为空时等待数据到来
        //考虑到CPU虚假唤醒的情况，就算wait被打破，仍然要确认queue是否为空
        while (working && queue.empty())
            pthread_cond_wait(&cond, &mtx);
        //弹出队首元素
        if (!queue.empty()) {
            item = queue.front();
            queue.pop();
            pthread_mutex_unlock(&mtx);
            return true;
        }
        //结束工作则返回false
        pthread_mutex_unlock(&mtx);
        return false;
    }

    //移除队首元素
    void pop() {
        pthread_mutex_lock(&mtx);
        if (!queue.empty()) {
            T front = queue.front();
            queue.pop();
            releaseFunc(front);
        }
        pthread_mutex_unlock(&mtx);
    }

    //清空队列
    void clear() {
        pthread_mutex_lock(&mtx);
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            T front = queue.front();
            queue.pop();
            releaseFunc(front);
        }
        pthread_mutex_unlock(&mtx);
    }

    //获取队列长度
    int size() {
        pthread_mutex_lock(&mtx);
        int size = queue.size();
        pthread_mutex_unlock(&mtx);
        return size;
    }

    //判断队列是否为空
    bool empty() {
        pthread_mutex_lock(&mtx);
        bool empty = queue.empty();
        pthread_mutex_unlock(&mtx);
        return empty;
    }

    //开始或停止工作
    void setWorking(bool working) {
        pthread_mutex_lock(&mtx);
        this->working = working;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mtx);
    }

    //是否处于工作状态
    bool isWorking() {
        return working;
    }
};

#endif


